﻿using MySql.Data.MySqlClient;
using SuperSocketTest.common;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//数据库连接池
namespace SuperServer.common
{
    public class ConnectionPool
    {
        private static ConnectionPool connectionPool = null;//连接池管理对象
        private static Object objLock = typeof(ConnectionPool);//管理对象示例
        private int maxSize;//池中最大连接数
        private int used = 0;//已使用连接数  已存在的连接数
        //private List<MySqlConnection> pool;//保存连接的集合
        private BlockingCollection<MySqlConnection> pool;
        private String ConnectionStr = "";//连接字符串

        private readonly object counterLock = new object(); // 锁对象

        private ConnectionPool()
        {
            //数据库连接字符串
            ConnectionStr = ConfigHelper.GetConnectionStringsConfig("MySqlConn");
            maxSize = 500;
            //创建可用链接的集合
            pool = new BlockingCollection<MySqlConnection>(maxSize);
        }

        //创建并获取连接池对象
        public static ConnectionPool getPool()
        {
            lock (objLock)
            {
                if (connectionPool == null)
                {
                    connectionPool = new ConnectionPool();
                }
                return connectionPool;
            }
        }

        //获取连接池中的连接
        /*public MySqlConnection getConnection()
        {

            LogHelper.WriteLog("当前数据库连接数"+pool.Count.ToString());
            lock (pool)
            {
                MySqlConnection temp = null;
                //可用连接大于0
                if (pool.Count > 0)
                {
                    //获取第一个可用连接
                    temp = (MySqlConnection)pool[0];
                    pool.RemoveAt(0);
                    //失败
                    if (!isUsefull(temp))
                    {
                        //连接不可用
                        used--;
                        temp.Close();
                        temp = getConnection();
                    }
                }
                else
                {
                    //可使用户的连接小于连接数量
                    if (used <= maxSize)
                    {
                        try
                        {
                            //创建连接
                            temp = CreateConnection(temp);
                        }
                        catch (Exception ex)
                        {
                            LogHelper.WriteLog("数据库连接池错误", ex);
                        }
                    }
                }
                //连接为null
                if (temp == null)
                {
                    //达到最大连接数递归调用获取连接 否则创建新连接
                    if (used <= maxSize)
                    {
                        temp = getConnection();
                    }
                    else
                    {
                        temp = CreateConnection(temp);
                    }
                }
                return temp;
            }
        }*/

        public MySqlConnection getConnection(int retry = 0)
        {
            if (retry >= 3)
            {
                throw new Exception("重试次数过多");
            }
            retry++;
            MySqlConnection temp = null;
            //可用连接大于0
            if (pool.Count > 0 && pool.TryTake(out temp))
            {
                //获取第一个可用连接
                /*temp = (MySqlConnection);
                pool.RemoveAt(0);*/

                if (isUsefull(temp))
                {
                    return temp;
                }
                else 
                {
                    
                    temp.Close();//关闭无效连接 注意不是放回连接池
                    reduceUsed();//已用连接数减一

                    Thread.Sleep(20 * 2 ^ retry);
                    return getConnection(retry);
                }
            }
            else
            {
                //可使用户的连接小于连接数量 used<maxSise
                if (incrementUsed())
                {
                    try
                    {
                        //创建连接
                        return CreateConnection();
                        /*return temp;*/
                    }
                    catch (Exception ex)
                    {
                        LogHelper.WriteLog("数据库连接创建错误", ex);
                    }
                }
            }
            throw new Exception("达到连接池最大连接数");
            

            //LogHelper.WriteLog("当前数据库连接数" + pool.Count.ToString());
            /*lock (pool)
            {
                MySqlConnection temp = null;
                //可用连接大于0
                if (pool.Count > 0 && pool.TryTake(out temp))
                {
                    //获取第一个可用连接
                    *//*temp = (MySqlConnection);
                    pool.RemoveAt(0);*//*

                    if (isUsefull(temp))
                    {
                        return temp;
                    }
                    else
                    {
                        closeConnection(temp);
                        return getConnection();
                    }
                    
                }
                else
                {
                    //可使用户的连接小于连接数量
                    if (used <= maxSize)
                    {
                        try
                        {
                            //创建连接
                            temp = CreateConnection(temp);
                            return temp;
                        }
                        catch (Exception ex)
                        {
                            LogHelper.WriteLog("数据库连接池错误", ex);
                        }
                    }
                }
                throw new Exception("达到连接池最大连接数");
            }*/
        }

        private void reduceUsed()
        {
            lock (counterLock)
            {
                used--;
            }
        }

        private int getUsed()
        {
            lock (counterLock)
            {
                return used;
            }
        }

        private bool incrementUsed()
        {
            lock (counterLock)
            {
                if (used < maxSize)
                {
                    used++;
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        //创建连接
        private MySqlConnection CreateConnection()
        {
            //创建连接
            if (incrementUsed())//没有达到连接数上线，连接数+1
            {
                MySqlConnection conn = new MySqlConnection(ConnectionStr);
                conn.Open();
                //可用连接数加一
                /*used++;*/
                return conn;
/*                return temp;
*/            }
            else
            {
                throw new Exception("连接达到最大数量"+getUsed());
            }
            
        }

        public void closeConnection(MySqlConnection con)
        {

            if (con != null && con.State == ConnectionState.Open)
            {
                if (pool.Count < maxSize)
                {
                    //将连接添加在连接池中
                    pool.TryAdd(con);
                }
                else
                {
                    con.Close();
                }

            }

        }

        //关闭连接
        /*public void closeConnection(MySqlConnection con)
        {
            
            if (con != null && con.State == ConnectionState.Open)
            {
                if(pool.Count < maxSize)
                {
                    //将连接添加在连接池中
                    pool.Add(con);
                }
                else
                {
                    con.Close();
                }
                    
            }
            
        }*/

        //连接是否可用
        private bool isUsefull(MySqlConnection con)
        {
            //主要用于不同用户
            bool result = false;
            if (con != null)
            {
                string sql = "select 1";//随便执行对数据库操作
                MySqlCommand cmd = new MySqlCommand(sql, con);
                try
                {
                    cmd.ExecuteScalar().ToString();

                    result = true;
                }
                catch
                {
                    result = false;
                }

            }
            return result;
        }


    }
}
